home *** CD-ROM | disk | FTP | other *** search
- /*
- * MISCWIN.C vi:ts=4
- *
- * Copyright (c) Eddy Carroll, September 1994.
- *
- * This module contains miscellaneous functions associated with
- * the SnoopDos GUI, but nevertheless not directly tied to any
- * particular window.
- *
- */
-
- #include "system.h"
- #include "snoopdos.h"
- #include "gui.h"
-
- #if 0
- #define DB(s) KPrintF(s)
- #else
- #define DB(s)
- #endif
-
- /*
- * Four dummy requesters for use when disabling window input
- */
- struct FileRequester *SnoopDosFR;
-
- APTR AG_Context;
- struct NewAmigaGuide AG_NewGuide;
- char *PendingAGuideMsg;
-
- extern struct TextAttr TopazFontAttr;
- extern struct TextAttr SystemFontAttr;
- extern struct TextAttr WindowFontAttr;
- extern struct TextAttr BufferFontAttr;
-
- /*
- * Now our busy pointer for V37 users (borrowed from ToolMaker)
- */
- UWORD __chip WaitPointer[36] = {
- 0x0000, 0x0000, 0x0400, 0x07C0, 0x0000, 0x07C0, 0x0100, 0x0380,
- 0x0000, 0x07E0, 0x07C0, 0x1FF8, 0x1FF0, 0x3FEC, 0x3FF8, 0x7FDE,
- 0x3FF8, 0x7FBE, 0x7FFC, 0xFF7F, 0x7EFC, 0xFFFF, 0x7FFC, 0xFFFF,
- 0x3FF8, 0x7FFE, 0x3FF8, 0x7FFE, 0x1FF0, 0x3FFC, 0x07C0, 0x1FF8,
- 0x0000, 0x07E0, 0x0000, 0x0000
- };
-
- ULONG __chip FileButtonData[] = {
- 0x0FF00000, 0x0C180000, 0x0C140000, 0x0C120000, 0x0C1F0000,
- 0x0C030000, 0x0C030000, 0x0C030000, 0x0C030000, 0x0FFF0000,
- };
-
- ULONG __chip FontButtonData[] = {
- 0x0FE00000, 0x09200000, 0x01000000, 0x017F0000, 0x01490000,
- 0x01080000, 0x01080000, 0x00080000, 0x00080000, 0x00080000,
- };
-
- /*
- * This structure holds all the information we need to know about
- * one of our custom images
- */
- struct CustomBitMap {
- struct Image image;
- struct Image altimage;
- struct BitMap bitmap;
- struct RastPort rport;
- };
-
- struct CustomImage {
- struct CustomBitMap image[2];
- int size;
- };
-
- /*****************************************************************************
- *
- * Start of functions!
- *
- *****************************************************************************/
-
- /*
- * DisableWindow(window, requester)
- *
- * Disables the specified window by displaying a dummy requester in it
- * and turning on the wait pointer. It is assumed that the window
- * exists and has not been disabled already.
- */
- void DisableWindow(struct Window *win, struct Requester *req)
- {
- InitRequester(req);
- if (Request(req, win)) {
- /*
- * Use the new V39 system busy pointer if possible, else
- * drop back to our own busy pointer
- */
- if (IntuitionBase->LibNode.lib_Version >= 39)
- SetWindowPointer(win,
- WA_BusyPointer, TRUE,
- WA_PointerDelay, TRUE,
- TAG_DONE);
- else
- SetPointer(win, WaitPointer, 16, 16, -6, 0);
- }
- }
-
- /*
- * EnableWindow()
- *
- * Enables the specified window by removing the dummy requester
- * placed inside it earlier. You must have called DisableWindow()
- * with the same parameters first.
- */
- void EnableWindow(struct Window *win, struct Requester *req)
- {
- EndRequest(req, win);
- ClearPointer(win);
- }
-
- /*
- * DisableAllWindows()
- *
- * Disables all windows by opening a dummy requester in them and
- * setting the window pointer to busy. Calls to this function
- * nest, so be sure to call EnableAllWindows the correct number
- * of times. This is intended for use when displaying modal
- * requesters (e.g. ASL, error messages, etc.)
- */
- void DisableAllWindows(void)
- {
- DisableNestCount++;
- if (DisableNestCount == 1) {
- if (MainWindow) {
- /*
- * If we are disabling the main window, we won't be able
- * to respond to IDCMP_SIZEVERIFY messages, so instead, we
- * just stop requesting them. This lets the user resize the
- * window when we have a file/font requester up, even though
- * it won't redraw until the requester is finished.
- */
- ModifyIDCMP(MainWindow,MainWindow->IDCMPFlags & ~IDCMP_SIZEVERIFY);
- DisableWindow(MainWindow, &MainRequester);
- }
- if (SetWindow) DisableWindow(SetWindow, &SetRequester);
- if (FuncWindow) DisableWindow(FuncWindow, &FuncRequester);
- if (FormWindow) DisableWindow(FormWindow, &FormRequester);
- }
- }
-
- /*
- * EnableAllWindows()
- *
- * Re-enables all windows disabled by calling DisableAllWindows()
- */
- void EnableAllWindows(void)
- {
- DisableNestCount--;
- if (DisableNestCount == 0) {
- if (SetWindow) EnableWindow(SetWindow, &SetRequester);
- if (FuncWindow) EnableWindow(FuncWindow, &FuncRequester);
- if (FormWindow) EnableWindow(FormWindow, &FormRequester);
- if (MainWindow) {
- /*
- * Because the user might have resized the main window
- * while we were disabled, causing us to miss the resize
- * message (which happens when IDCMP_SIZEVERIFY is active)
- * we check to see if the size has changed and if it has,
- * cause a fake RESIZE message to be sent to ourself.
- */
- EnableWindow(MainWindow, &MainRequester);
- ModifyIDCMP(MainWindow, MainWindow->IDCMPFlags | IDCMP_SIZEVERIFY);
- if (MainWindow->Width != CurWindowWidth ||
- MainWindow->Height != CurWindowHeight) {
- SizeWindow(MainWindow, 0, 0);
- }
- }
- }
- }
-
- /*
- * RecordWindowSizes()
- *
- * Records the current size and position of all open windows on the
- * display so that they can be re-opened in the same position next time.
- * Usually called before a window is closed, but may also be called
- * when (for example) settings are being saved.
- */
- void RecordWindowSizes(void)
- {
- if (MainWindow) {
- CurSettings.MainWinLeft = MainWindow->LeftEdge;
- CurSettings.MainWinTop = MainWindow->TopEdge;
- CurSettings.MainWinWidth = MainWindow->Width;
- CurSettings.MainWinHeight = MainWindow->Height;
- }
- if (FormWindow) {
- CurSettings.FormWinLeft = FormWindow->LeftEdge;
- CurSettings.FormWinTop = FormWindow->TopEdge;
- }
- if (FuncWindow) {
- CurSettings.FuncWinLeft = FuncWindow->LeftEdge;
- CurSettings.FuncWinTop = FuncWindow->TopEdge;
- }
- if (SetWindow) {
- CurSettings.SetupWinLeft = SetWindow->LeftEdge;
- CurSettings.SetupWinTop = SetWindow->TopEdge;
- }
- }
-
- /*
- * ShowError(errormsg)
- *
- * Displays the specified error message in a requester (on the same
- * screen as the main SnoopDos window if possible, else on the
- * default window), waits for an OKAY click, and returns.
- */
- void ShowError(char *errormsg, ...)
- {
- static struct EasyStruct es = {
- sizeof(struct EasyStruct),
- 0,
- "SnoopDos",
- NULL,
- NULL
- };
- int pausestate = Paused;
-
- Paused = 0;
-
- es.es_TextFormat = errormsg;
- es.es_GadgetFormat = MSG(MSG_ERROR_OKAY);
- DisableAllWindows();
- /*
- * If MainWindow is NULL, then the requester will appear on
- * the default public screen
- */
- EasyRequestArgs(MainWindow, &es, 0, (&errormsg)+1);
- EnableAllWindows();
- Paused = pausestate;
- }
-
- /*
- * GetResponse(prompt, message, params, ...)
- *
- * Displays an easy requester with the specified prompts, waits for the
- * user to click on an option, then returns the selected option.
- *
- * Note that options are numbered 1,2,3....,0 with the leftmost gadget
- * returning 1 and the rightmost gadget returning 0.
- */
- int GetResponse(char *prompts, char *reqmsg, ...)
- {
- static struct EasyStruct es = {
- sizeof(struct EasyStruct),
- 0,
- "SnoopDos",
- NULL,
- NULL
- };
- int pausestate = Paused;
- int choice;
-
- Paused = 0;
-
- es.es_TextFormat = reqmsg;
- es.es_GadgetFormat = prompts;
- DisableAllWindows();
- choice = EasyRequestArgs(MainWindow, &es, 0, (&reqmsg)+1);
- EnableAllWindows();
- Paused = pausestate;
- return (choice);
- }
-
- /*
- * MaxTextLen(font, textarray)
- *
- * Returns the length (in pixels) of the longest string in the given
- * zero-terminated array of message IDs, using the given font.
- */
- int MaxTextLen(struct TextFont *font, int *ids)
- {
- struct RastPort rp;
- int maxlen = 0;
-
- InitRastPort(&rp);
- SetFont(&rp, font);
-
- while (*ids) {
- char *msg = MSG(*ids++);
- int len = TextLength(&rp, msg, strlen(msg));
-
- if (len > maxlen)
- maxlen = len;
- }
- return (maxlen);
- }
-
- /*
- * GetTextLen(font, msg)
- *
- * Returns the length (in pixels) of the given message indicated by the
- * message ID, when rendered in the given font.
- */
- int GetTextLen(struct TextFont *font, char *msg)
- {
- struct RastPort rp;
-
- InitRastPort(&rp);
- SetFont(&rp, font);
- return (TextLength(&rp, msg, strlen(msg)));
- }
-
- /*
- * AddKeyShortcut(shortcut, gadid, msgid)
- *
- * Checks the string corresponding to msgid for an underlined
- * character. If one is found, then a corresponding entry is
- * made in the shortcut array with that gadget ID.
- *
- * For alphabetic shortcuts, we make entries for both the lower
- * and upper case versions of the key (since we might have
- * strings like "_Cancel" and "U_se" and we want both kinds
- * to be treated identically).
- */
- void AddKeyShortcut(UBYTE *shortcut, int gadid, int msgid)
- {
- UBYTE *p = MSG(msgid);
-
- while (*p) {
- if (*p++ == '_') {
- UBYTE ch = *p;
-
- if (ch >= 'a' && ch <= 'z')
- ch &= 0x5F;
-
- shortcut[ch] = gadid;
- if (ch >= 'A' && ch <= 'Z')
- shortcut[ch + 32] = gadid;
- return;
- }
- }
- }
-
- /*
- * ShowGadget(window, gadget, type)
- *
- * Activates or deactives the described gadget, by showing it in
- * a GADGET_DOWN or GADGET_UP rendered state. This is mainly used
- * to give the user direct feedback as to what's happening when
- * they hit a keyboard shortcut.
- *
- * Automatically ignores disabled gadgets.
- */
- void ShowGadget(struct Window *win, struct Gadget *gad, int type)
- {
- if ((gad->Flags & GFLG_DISABLED) == 0) {
- int gadpos = RemoveGadget(win, gad);
-
- if (type == GADGET_DOWN)
- gad->Flags |= GFLG_SELECTED;
- else
- gad->Flags &= ~GFLG_SELECTED;
- AddGadget(win, gad, gadpos);
- RefreshGList(gad, win, NULL, 1);
- }
- }
-
- /*
- * MyOpenFont()
- *
- * Tries to open the specified font. If we can't open diskfont.library,
- * then falls back to the ROM OpenFont() in graphics.library. We do
- * this so that we can still run, even when there is no diskfont.library
- * around.
- *
- * Returns a pointer to the opened font, or NULL for failure.
- */
- struct TextFont *MyOpenFont(struct TextAttr *textattr)
- {
- if (DiskfontBase)
- return OpenDiskFont(textattr);
- else
- return OpenFont(textattr);
- }
-
- /*
- * CheckForASL()
- *
- * Tries to load asl.library and displays an error requester if it
- * can't be located. Returns TRUE if successful, or FALSE if it
- * couldn't be loaded. All functions using asl.library functions
- * must call this first.
- *
- * We do it like this since it's useful to be able to run SnoopDos
- * even when asl.library isn't around.
- */
- int CheckForASL(void)
- {
- if (!DiskfontBase) {
- DiskfontBase = OpenLibrary("diskfont.library", 0);
- if (!DiskfontBase) {
- ShowError(MSG(MSG_ERROR_NO_DISKFONT));
- return (FALSE);
- }
- }
- if (!AslBase) {
- AslBase = OpenLibrary("asl.library", 0);
- if (!AslBase) {
- ShowError(MSG(MSG_ERROR_NO_ASL));
- return (FALSE);
- }
- }
- return (TRUE);
- }
-
- /*
- * SelectFont(win, fonttype)
- *
- * Requests a font from the user of the appropriate type (either
- * FONTSEL_WINDOW or FONTSEL_BUFFER). Returns TRUE if a font was
- * successfully chosen, else FALSE. win is the window this
- * requester is associated with (used to choose the correct
- * opening screen).
- *
- * If successful, the font requester (WindowFR or BufferFR) will
- * hold details of the selected font.
- */
- int SelectFont(struct Window *win, int fonttype)
- {
- struct FontRequester **fontreq;
- struct TextAttr *fontattr;
- struct TextAttr *reqfont;
- struct TextFont *tempfont;
- int fixedwidth;
- char *title;
- int retval;
- int pausestate = Paused;
-
- if (!CheckForASL())
- return (FALSE);
-
- /*
- * Now a little check to make sure we can actually open
- * the current window font. If we can't, fall back to the
- * system font. (This should never arise, but if it does,
- * the user is in the unfortunate position of not being
- * able to change to a font that IS recognised, since the
- * font requester can't be opened!)
- */
- reqfont = &WindowFontAttr;
- tempfont = MyOpenFont(reqfont);
- if (tempfont)
- CloseFont(tempfont);
- else
- reqfont = &SystemFontAttr;
-
- /*
- * Next, initialise according to the font type being selected
- */
- if (fonttype == FONTSEL_BUFFER) {
- fontreq = &BufferFR;
- fontattr = &BufferFontAttr;
- title = MSG(MSG_BFONT_TITLE);
- fixedwidth = TRUE;
- } else {
- fontreq = &WindowFR;
- fontattr = &WindowFontAttr;
- title = MSG(MSG_GFONT_TITLE);
- fixedwidth = FALSE;
- }
-
- if (*fontreq == NULL) {
- *fontreq = (struct FontRequester *)
- AllocAslRequestTags(ASL_FontRequest,
- ASLFO_PrivateIDCMP, TRUE,
- ASLFO_TitleText, title,
- ASLFO_PositiveText, MSG(MSG_ERROR_OKAY),
- ASLFO_NegativeText, MSG(MSG_ERROR_CANCEL),
- ASLFO_FixedWidthOnly, fixedwidth,
- ASLFO_InitialHeight, SnoopScreen->Height*3/4,
- TAG_DONE);
- if (!*fontreq) {
- ShowError(MSG(MSG_ERROR_OPENFONT));
- return (FALSE);
- }
- }
- Paused = 0;
- DisableAllWindows();
- retval = AslRequestTags(*fontreq,
- ASLFO_TextAttr, reqfont,
- ASLFO_Window, win,
- ASLFO_InitialName, fontattr->ta_Name,
- ASLFO_InitialSize, fontattr->ta_YSize,
- TAG_DONE);
- EnableAllWindows();
- Paused = pausestate;
-
- if (retval && fonttype == FONTSEL_BUFFER) {
- /*
- * Now do an additional check to ensure we really got a
- * non-proportional font, since the ASL requester (as of V39)
- * can sometimes return a proportional font even when the
- * FixedWidthOnly tag is set. If we got a proportional font,
- * ignore the selection.
- */
- struct TextFont *font = MyOpenFont(&BufferFR->fo_Attr);
-
- if (!font || (font->tf_Flags & FPF_PROPORTIONAL)) {
- ShowError(MSG(MSG_ERROR_FONT_PROPORTIONAL));
- retval = FALSE;
- }
- if (font)
- CloseFont(font);
- }
- return (retval);
- }
-
- /*
- * SelectFile(char *newname, char *defname, win, type)
- *
- * Requests a file from the user of the appropriate type:
- *
- * FILESEL_LOADCONFIG - Loading a configuration
- * FILESEL_SAVECONFIG - Saving a configuration
- * FILESEL_DEFLOGNAME - Default log filename
- * FILESEL_NEWLOGNAME - Current log filename
- *
- * Returns TRUE for success, FALSE for failure.
- *
- * newname is the buffer to store the full pathname of the selected file.
- * defname is the default path/filename to use in the requester.
- *
- * defname and newname may both point to the same string -- newname is
- * only updated if a file is actually selected.
- */
- int SelectFile(char *newname, char *defname, struct Window *win, int type)
- {
- char pathname[100];
- char filename[50];
- struct TextAttr *reqfont;
- struct TextFont *tempfont;
- int titleid;
- int retval;
- int pausestate = Paused;
- int savemode;
- int n;
-
- if (!CheckForASL())
- return (FALSE);
-
- switch (type) {
- case FILESEL_LOADCONFIG: titleid = MSG_ASL_LOADCONFIG; break;
- case FILESEL_SAVECONFIG: titleid = MSG_ASL_SAVECONFIG; break;
- case FILESEL_DEFLOGNAME: titleid = MSG_ASL_DEFLOGNAME; break;
- case FILESEL_NEWLOGNAME: titleid = MSG_ASL_NEWLOGNAME; break;
- case FILESEL_SAVEWINDOW: titleid = MSG_ASL_SAVEWINDOW; break;
- case FILESEL_SAVEBUFFER: titleid = MSG_ASL_SAVEBUFFER; break;
- }
- savemode = (type != FILESEL_LOADCONFIG);
-
- /*
- * Now a little check to make sure we can actually open
- * the current window font. If we can't, fall back to the
- * system font.
- */
- reqfont = &WindowFontAttr;
- tempfont = MyOpenFont(reqfont);
- if (tempfont)
- CloseFont(tempfont);
- else
- reqfont = &SystemFontAttr;
-
- strcpy(filename, FilePart(defname));
- n = PathPart(defname) - defname;
- if (n)
- strncpy(pathname, defname, n);
- pathname[n] = '\0';
-
- if (SnoopDosFR == NULL) {
- SnoopDosFR = (struct FileRequester *)
- AllocAslRequestTags(ASL_FileRequest,
- ASLFR_PrivateIDCMP, TRUE,
- ASLFR_PositiveText, MSG(MSG_ERROR_OKAY),
- ASLFR_NegativeText, MSG(MSG_ERROR_CANCEL),
- ASLFR_RejectIcons, TRUE,
- ASLFR_InitialHeight, SnoopScreen->Height*3/4,
- TAG_DONE);
- if (!SnoopDosFR) {
- ShowError(MSG(MSG_ERROR_OPENFILEREQ));
- return (FALSE);
- }
- }
- /*
- * It's important that we disable windows while the
- * file requester is displayed, otherwise users might
- * become confused
- */
- Paused = 0;
- DisableAllWindows();
- retval = AslRequestTags(SnoopDosFR,
- ASLFR_TitleText, MSG(titleid),
- ASLFR_Window, win,
- ASLFR_TextAttr, reqfont,
- ASLFR_InitialFile, filename,
- ASLFR_InitialDrawer, pathname,
- ASLFR_DoSaveMode, savemode,
- TAG_DONE);
- EnableAllWindows();
- Paused = pausestate;
- /*
- * Now build our return filename. If no output filename was selected
- * but a directory was given, then we only allow a successful if
- * the "directory" is actually a device -- if it's a real directory
- * we return failure (since you can't save or load a directory).
- *
- * We even return failure if a device is specified as the directory
- * and we're trying to load a file, since loading from a printer
- * makes no sense. (Mind you, loading a config file from a CON: file
- * might be an interesting way to provide a built-in command line
- * interpreter!)
- */
- if (retval) {
- if (*SnoopDosFR->fr_File ||
- (savemode && !IsFileSystem(SnoopDosFR->fr_Drawer)))
- {
- strcpy(newname, SnoopDosFR->fr_Drawer);
- AddPart(newname, SnoopDosFR->fr_File, 255);
- } else
- retval = FALSE;
- }
- return (retval);
- }
-
- /*
- * InitFonts()
- *
- * Initialises our default fonts (system, topaz) and
- * updates the current font settings to whichever font is
- * appropriate, if they have not already been set to
- * a particular font.
- */
- void InitFonts(void)
- {
- /*
- * We have four fonts in total; the current gadget and buffer fonts,
- * the system font, and finally topaz 8 point. If we fail to open
- * a window using either of the first two, we will try again using
- * the third and finally using the fourth before giving up.
- *
- * We default to having the gadget font be the same as the screen
- * font, and having the buffer font the same as the system font.
- */
- strcpy(SystemFontName, GfxBase->DefaultFont->tf_Message.mn_Node.ln_Name);
- SystemFontAttr.ta_YSize = GfxBase->DefaultFont->tf_YSize;
- BufferFontAttr.ta_YSize = BufferFontSize;
- WindowFontAttr.ta_YSize = WindowFontSize;
-
- if (BufferFontSize == 0) {
- strcpy(BufferFontName, SystemFontName);
- BufferFontAttr.ta_YSize = SystemFontAttr.ta_YSize;
- BufferFontSize = BufferFontAttr.ta_YSize;
- }
-
- if (SnoopScreen && WindowFontSize == 0) {
- strcpy(WindowFontName, SnoopScreen->Font->ta_Name);
- WindowFontAttr.ta_YSize = SnoopScreen->Font->ta_YSize;
- WindowFontSize = WindowFontAttr.ta_YSize;
- }
- }
-
- /*
- * SetupScreen()
- *
- * Initialises the font and other variables which depend on the
- * user's chosen screen. This is called prior to opening any
- * windows on a screen.
- *
- * If we can't open on the user's desired screen (maybe it doesn't
- * exist) then we fall back to Workbench. If we can't even open on
- * Workbench, then we're really in trouble and should probably quit.
- *
- * We maintain the screen info until CleanupScreen() is called (usually
- * because SnoopDos is going into a hidden state).
- *
- * Returns TRUE for success, false for failure. SnoopScreen can also
- * be checked at any time to see if we have a valid screen or not.
- *
- */
- int SetupScreen(void)
- {
- struct ColorMap *cm;
- struct Screen *scr;
- char *scrname = NULL; /* Default is default public screen */
- struct List *psl;
- struct PubScreenNode *psn;
-
- /*
- * First, let's locate the screen we want, according to the
- * user's preference. If we can't open the preferred screen,
- * we try again with the default public screen. If we can't
- * open the default public screen, we try Workbench. If we
- * can't open THAT, then we're really screwed.
- */
- if (SnoopScreen)
- CleanupScreen();
-
- switch (CurSettings.Setup.ScreenType) {
-
- case SCREEN_FRONT:
- /*
- * We want to open on the front public screen if possible.
- * The only way to find out if the current screen is a
- * public screen is to read IntuitionBase->FirstScreen and
- * then try and find a match for it on the public screen list.
- * If we do, then the public screen structure will give the
- * public name of the screen, which we can then use to
- * lock it.
- */
- psl = (void *)LockPubScreenList();
- if (psl) {
- scr = IntuitionBase->FirstScreen;
- FORLIST(psl, psn) {
- if (psn->psn_Screen == scr) {
- scrname = psn->psn_Node.ln_Name;
- break;
- }
- }
- UnlockPubScreenList();
- }
- break;
-
- case SCREEN_NAMED:
- scrname = CurSettings.Setup.ScreenName;
- break;
- }
- scr = LockPubScreen(scrname);
- if (!scr && scrname)
- scr = LockPubScreen(NULL);
-
- if (!scr) {
- scr = LockPubScreen("Workbench");
- if (!scr)
- return (FALSE);
- }
- BorderLeft = scr->WBorLeft;
- BorderRight = scr->WBorRight;
- BorderTop = scr->WBorTop;
- BorderBottom = scr->WBorBottom;
- ScreenWidth = scr->Width;
- ScreenHeight = scr->Height;
- TitlebarHeight = BorderTop + scr->Font->ta_YSize + 1;
-
- /*
- * Now calculate aspect ratio of screen, so we can scale the
- * horizontal scroll bar accordingly.
- */
- SquareAspect = 1; /* Assume square aspect ratio */
- GadgetHeight = HI_GADGET_HEIGHT;
- GadgetSpacing = HI_GADGET_SPACING;
- cm = scr->ViewPort.ColorMap;
- if (cm) {
- struct TagItem ti[] = {
- VTAG_VIEWPORTEXTRA_GET, NULL,
- VTAG_END_CM, NULL
- };
- if (VideoControl(cm, ti) == NULL) {
- struct ViewPortExtra *vpe = (struct ViewPortExtra *)ti[0].ti_Data;
- struct Rectangle *rect = &vpe->DisplayClip;
-
- if ((rect->MaxX - rect->MinX)/2 > (rect->MaxY - rect->MinY)) {
- SquareAspect = 0;
- GadgetHeight = LO_GADGET_HEIGHT;
- GadgetSpacing = LO_GADGET_SPACING;
- }
- }
- }
- SnoopScreen = scr;
- ScreenDI = GetScreenDrawInfo(SnoopScreen);
- /*
- * Get the sizing image used by windows. We need this info
- * so that we can align our scroll arrows and scroll bars
- * correctly.
- */
- ScreenResolution = (SnoopScreen->Flags & SCREENHIRES) ? SYSISIZE_MEDRES :
- SYSISIZE_LOWRES;
- SizeImage = (struct Image *)NewObject(NULL, "sysiclass",
- SYSIA_DrawInfo, ScreenDI,
- SYSIA_Which, SIZEIMAGE,
- SYSIA_Size, ScreenResolution,
- TAG_END);
- if (!SizeImage) {
- CleanupScreen();
- return (NULL);
- }
- InitFonts();
- return (TRUE);
- }
-
- /*
- * CleanupScreen()
- *
- * Frees resources associated with the screen. Called when
- * SnoopDos is about to go into HIDE mode.
- */
- void CleanupScreen(void)
- {
- if (SizeImage) {
- DisposeObject(SizeImage);
- SizeImage = NULL;
- }
- if (SnoopScreen) {
- if (ScreenDI) {
- FreeScreenDrawInfo(SnoopScreen, ScreenDI);
- ScreenDI = NULL;
- }
- UnlockPubScreen(NULL, SnoopScreen);
- SnoopScreen = NULL;
- }
- }
-
- /*
- * CleanupWindows()
- *
- * Frees all resources allocated in windows module
- */
- void CleanupWindows(void)
- {
- CleanupMainWindow();
- CleanupSubWindows();
- CleanupScreen();
- if (WindowFR) FreeAslRequest(WindowFR), WindowFR = NULL;
- if (BufferFR) FreeAslRequest(BufferFR), BufferFR = NULL;
- if (SnoopDosFR) FreeAslRequest(SnoopDosFR), SnoopDosFR = NULL;
- }
-
- /*
- * ShowAGuide(cmdstring)
- *
- * Attempts to open AmigaGuide and display help on the specified
- * topic. (The cmd string should be an actual AmigaGuide command
- * in the form "LINK keyword".)
- *
- * After calling this function, you should call CleanupHelp()
- * before exiting the program, to ensure that the AmigaGuide
- * system is safely closed down.
- *
- * If SnoopDos is running on a separate screen to the one currently
- * in use by AmigaGuide, AmigaGuide will be shut down and re-opened
- * on the current screen.
- *
- * Returns true for success, false for failure. However, it puts
- * up its own error messages, so you can pretty much ignore the
- * return value. (Calling CleanupAGuide() is always safe.)
- *
- * Note: cmdstring should be a permanent string, not a temporary
- * (at least until the next time this function is called!)
- */
- int ShowAGuide(char *cmdstring)
- {
- if (!AmigaGuideBase) {
- AmigaGuideBase = OpenLibrary("amigaguide.library", 34);
- if (!AmigaGuideBase) {
- ShowError(MSG(MSG_ERROR_NO_AMIGAGUIDE));
- return (FALSE);
- }
- }
- if (!CheckForScreen())
- return (FALSE);
-
- if (AG_Context && AG_NewGuide.nag_Screen != SnoopScreen) {
- CloseAmigaGuide(AG_Context);
- AG_Context = NULL;
- AmigaGuideMask = 0;
- }
- if (!AG_Context) {
- /*
- * AmigaGuide wasn't already running so open it up on
- * our current screen
- *
- * The docs say that we must ensure the screen pointer
- * AmigaGuide gets remains valid for the duration of
- * AmigaGuide use. What happens if someone closes the
- * main SnoopDos window causing us to remove our lock on
- * the public screen?
- *
- * Well, since earlier, we ensured that we always force
- * AmigaGuide to open on our current screen, and since a
- * public screen can't close as long as AmigaGuide has some
- * windows on it, the only potential for a problem would be
- * if AmigaGuide tried to open a new window on its screen
- * on its own -- and it will never do that since we always
- * control it via this function.
- */
- static char copycmd[80];
-
- AG_NewGuide.nag_Lock = NULL;
- AG_NewGuide.nag_Name = MSG(MSG_HELPFILE_NAME);
- AG_NewGuide.nag_Screen = SnoopScreen;
- AG_NewGuide.nag_ClientPort = HELP_AREXX_PORT;
- AG_NewGuide.nag_BaseName = HELP_BASENAME;
- AG_NewGuide.nag_Flags = HTF_CACHE_NODE;
-
- AG_Context = OpenAmigaGuideAsync(&AG_NewGuide, TAG_DONE);
- if (!AG_Context) {
- ShowError(MSG(MSG_ERROR_CREATE_AMIGAGUIDE));
- return (FALSE);
- }
- AmigaGuideMask = AmigaGuideSignal(AG_Context);
- /*
- * Now since AmigaGuide won't initialise immediately, it's
- * no use sending this help request to it -- we need to wait
- * until it tells us that it's ready for action. So, we
- * remember the command that was to be sent, and when we
- * get the okay from AmigaGuide, we can send it (see
- * HandleAGuideMsgs() below.)
- *
- * Also, since sometimes the string that we are sent is only
- * temporary (e.g. from an ARexx message) we need to make a
- * copy of it.
- */
- strcpy(copycmd, cmdstring);
- PendingAGuideMsg = copycmd;
- return (TRUE);
- }
-
- /*
- * Usual case: just send the command directly to AmigaGuide
- */
- SendAmigaGuideCmd(AG_Context, cmdstring, NULL);
- return (TRUE);
- }
-
- /*
- * HandleAGuideMsgs()
- *
- * Handles any AmigaGuide messages (as indicate by a signal
- * arriving that matches AmigaGuideMask)
- */
- void HandleAGuideMsgs(void)
- {
- struct AmigaGuideMsg *agm;
- int unloadhelp = 0;
-
- if (!AmigaGuideBase || !AG_Context)
- return;
-
- while ((agm = GetAmigaGuideMsg(AG_Context)) != NULL) {
- switch (agm->agm_Type) {
-
- case ActiveToolID:
- /*
- * The first time we try and display something,
- * AmigaGuide has to load first. We get this
- * message when it's finished loading, to let
- * us know we can now display the help.
- */
- if (PendingAGuideMsg) {
- SendAmigaGuideCmd(AG_Context, PendingAGuideMsg, NULL);
- PendingAGuideMsg = NULL;
- }
- break;
-
- case ToolCmdReplyID:
- case ToolStatusID:
- case ShutdownMsgID:
- if (agm->agm_Pri_Ret){
- if (agm->agm_Sec_Ret == HTERR_CANT_OPEN_DATABASE) {
- ShowError(MSG(MSG_ERROR_AGUIDE_CANT_OPEN),
- MSG(MSG_HELPFILE_NAME));
- unloadhelp = 1;
- } else {
- ShowError(MSG(MSG_ERROR_AGUIDE_GENERIC),
- GetAmigaGuideString(agm->agm_Sec_Ret));
- }
- PendingAGuideMsg = NULL; /* Cancel any pending cmd */
- }
- break;
- }
- ReplyAmigaGuideMsg(agm);
- }
- if (unloadhelp)
- CleanupAGuide();
- }
-
- /*
- * CleanupAGuide()
- *
- * Frees all resources allocated by ShowAGuide(). Should only be
- * called at the end of the program.
- */
- void CleanupAGuide(void)
- {
- if (AG_Context) CloseAmigaGuide(AG_Context), AG_Context = NULL;
- if (AmigaGuideBase) CloseLibrary(AmigaGuideBase), AmigaGuideBase = NULL;
- AmigaGuideMask = 0;
- }
-
- /*
- * CreateCustomImage(imagetype, height)
- *
- * Creates an image of the specified type (IMAGE_FILE or IMAGE_FONT)
- * and returns a pointer to an image structure with details about
- * the image. The return value + 1 points to the same image, but
- * selected.
- *
- * height is the height of the image -- the width is fixed at 16 pixels.
- *
- * N.b. ScreenScreen should be valid when this function is called. You
- * should call FreeCustomImage(imageptr) to free up any memory allocated
- * when you're done.
- */
- struct Image *CreateCustomImage(int imagetype, int height)
- {
- #define NUM_ELS(x) (sizeof(x) / sizeof(x[0]))
-
- ULONG *imagedata = FileButtonData;
- int imbytesperrow = 4; /* Must be even */
- int imwidth = 20;
- int imheight = NUM_ELS(FileButtonData);
- int depth = SnoopScreen->RastPort.BitMap->Depth;
-
- struct CustomImage *ci;
- struct CustomBitMap *cbm;
- UBYTE *bitplane;
- int size;
-
- if (imagetype == IMAGE_FONT) {
- imagedata = FontButtonData;
- imheight = NUM_ELS(FontButtonData);
- if (height <= 12) /* Strip last line if gadget is tiny */
- imheight--;
- }
-
- /*
- * For the gadget, we need to store two full bitmaps, one for
- * the selected image and one for the unselected image. We
- * allocate a single structure in CHIP ram that holds all the
- * details we need.
- */
- size = sizeof(struct CustomImage) + imbytesperrow * height * depth * 2;
- ci = AllocMem(size, MEMF_CHIP | MEMF_CLEAR);
- if (!ci)
- return (NULL);
-
- ci->size = size;
-
- /*
- * Now initialise our two images -- the steps are almost identical
- * for each, except that one is filled and one is not.
- */
- bitplane = (UBYTE *)(ci+1);
- for (cbm = ci->image; cbm < &ci->image[2]; cbm++) {
- struct RastPort *rport = &cbm->rport;
- struct BitMap *bitmap = &cbm->bitmap;
- int fillpen;
- int textpen;
- int shinepen;
- int shadowpen;
- int planemask;
- int i;
-
- InitRastPort(rport);
- InitBitMap(bitmap, depth, imwidth, height);
-
- /*
- * Now initialise the plane pointers accordingly
- */
- for (i = 0; i < depth; i++) {
- bitmap->Planes[i] = bitplane;
- bitplane += (imbytesperrow * height);
- }
- rport->BitMap = bitmap;
-
- /*
- * Now we're ready to render our chosen image.
- * First let's draw the box and box highlight.
- * If we're drawing the selected state, we
- * invert the highlight colours to make the box
- * look indented.
- */
- shinepen = ScreenDI->dri_Pens[SHINEPEN];
- shadowpen = ScreenDI->dri_Pens[SHADOWPEN];
- if (cbm != ci->image) {
- int swappen = shinepen;
- shinepen = shadowpen;
- shadowpen = swappen;
- }
- SetDrMd(rport, JAM1);
- SetAPen(rport, shinepen);
- Move(rport, 0, height-1);
- Draw(rport, 0, 0);
- Draw(rport, imwidth-2, 0);
- Move(rport, 1, height-2);
- Draw(rport, 1, 1);
- SetAPen(rport, shadowpen);
- Move(rport, imwidth-1, 0);
- Draw(rport, imwidth-1, height-1);
- Draw(rport, 1, height-1);
- Move(rport, imwidth-2, 1);
- Draw(rport, imwidth-2, height-2);
-
- /*
- * Now, if we're on the second round, fill in the box
- * in the select colour
- */
- fillpen = 0;
- textpen = 1;
- if (cbm != ci->image) {
- fillpen = ScreenDI->dri_Pens[FILLPEN];
- textpen = ScreenDI->dri_Pens[FILLTEXTPEN];
- SetAPen(rport, fillpen);
- RectFill(rport, 2, 1, imwidth-3, height-2);
- }
- /*
- * Now the tricky bit -- we need to copy our image data
- * into the middle of the box icon we've just created.
- * Luckily, the data is already word-aligned for us so
- * we just need to worry about vertically centering it.
- * We use a little XOR trick to figure out which planes
- * need to be updated, and also to do the updating.
- */
- planemask = fillpen ^ textpen;
- for (i = 0; i < depth; i++) {
- if (planemask & (1 << i)) {
- ULONG *src = imagedata;
- ULONG *dest = ((ULONG *)(cbm->bitmap.Planes[i])) +
- (height - imheight) / 2;
- int j;
-
- for (j = 0; j < imheight; j++)
- *dest++ ^= *src++;
- }
- }
- /*
- * All done, now initialise the image accordingly
- */
- cbm->image.Width = imwidth;
- cbm->image.Height = height;
- cbm->image.Depth = depth;
- cbm->image.ImageData = (UWORD *)(cbm->bitmap.Planes[0]);
- cbm->image.PlanePick = (1 << depth) - 1;
- }
- /*
- * To ensure that our two image structures our consecutive,
- * we copy the second bitmap's image back into the first
- * image's bitmap's alternate image
- */
- ci->image[0].altimage = ci->image[1].image;
- return ((struct Image *)ci);
- }
-
- /*
- * FreeCustomImage(image)
- *
- * Release a custom image allocated earlier by CreateCustomImage()
- */
- void FreeCustomImage(struct Image *image)
- {
- if (image)
- FreeMem(image, ((struct CustomImage *)image)->size);
- }
-
- /*
- * ConvertIMsgToChar()
- *
- * Takes an IntuiMessage of IDCMP_RAWKEY and returns the single
- * character representation it corresponds to. If this isn't
- * possible (e.g. a HELP key or cursor key) then returns 0
- * instead.
- */
- int ConvertIMsgToChar(struct IntuiMessage *imsg)
- {
- static struct InputEvent ev; /* Ensure initalised to 0 */
- char buffer[9];
- int len;
-
- if (imsg->Class != IDCMP_RAWKEY)
- return (0);
-
- ev.ie_Class = IECLASS_RAWKEY;
- ev.ie_Code = imsg->Code;
- ev.ie_Qualifier = imsg->Qualifier;
- ev.ie_EventAddress = *(APTR *)imsg->IAddress;
- len = MapRawKey(&ev, buffer, 8, NULL);
- if (len != 1)
- return (0);
- return (buffer[0]);
- }
-